﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ComplexEventProcessing;
using Microsoft.ComplexEventProcessing.Adapters;
using IntroHost.EventType;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Diagnostics;
using System.Threading;


namespace WcfInputAdapter
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, IncludeExceptionDetailInFaults = true)]
    //public class WcfInputPointAdapter<TPayload>:TypedPointInputAdapter<TPayload>, ISimplelWcfEventType
    public class WcfInputPointAdapter:PointInputAdapter, ISimplelWcfEventType
    {
        private WcfInputAdapterConfing config;
        private static readonly int StopPollingPeriod = 1000; //msec
        private readonly Timer timer;
        private readonly object sync;
        private readonly ServiceHost host;
        private readonly Uri baseAddress;

        public WcfInputPointAdapter(WcfInputAdapterConfing config)
        {
            this.config = config;
            this.sync = new object();
            this.host = new ServiceHost(this);
            baseAddress = new Uri("http://localhost:8000/Metering");
            host.AddServiceEndpoint(typeof(ISimplelWcfEventType), new BasicHttpBinding(), baseAddress);
            ServiceMetadataBehavior smdb = new ServiceMetadataBehavior();
            smdb.HttpGetEnabled = true;
            smdb.HttpGetUrl = baseAddress;
            host.Description.Behaviors.Add(smdb);

            //Poll the adapter to determine when it is time to stop.
            this.timer = new Timer(CheckStopping);
            this.timer.Change(StopPollingPeriod, Timeout.Infinite);
        }

        private void CheckStopping(object state)
        {
            lock (this.sync)
            {
                if (AdapterState == AdapterState.Stopping)
                {
                    this.host.Close();
                    Stopped();
                }
                else
                {
                    // Check again after the polling period has elapsed.
                    this.timer.Change(StopPollingPeriod, Timeout.Infinite);
                }
            }
        }

        public override void Resume()
        {
        }

        public override void Start()
        {
            this.host.Open();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                ((IDisposable)this.host).Dispose();
            }
            base.Dispose(disposing);
        }

        string ISimplelWcfEventType.SubmitReading(string MeterId, double Value, DateTime Timestamp)
        {
            //Something to return to the client, success, fail, etc.  Empty untel set
            string retVal = "";  

            //I thought creating the SimpleEventType, which is what the generic eventually is
            //would let me just set the payload of the insert event to the data but this
            //doesn't work.  I get a cannot cast error since it doesn't know the type
            //until runtime.
            SimpleEventType eventPayload = new SimpleEventType();
            eventPayload.MeterId = MeterId;
            eventPayload.Value = Value;
            eventPayload.Timestamp = Timestamp;

            PointEvent pe = base.CreateInsertEvent();
            pe.SetField<string>(0, MeterId);
            pe.SetField<double>(2, Value);
            pe.SetField<DateTime>(1, Timestamp);
            pe.StartTime = DateTime.Now;

            Enqueue(ref pe);

            //Here is where the point event is created and the type is set.
            //When I break  into this, I see all the fields that I need to set 
            //but again, I can't set them at design time

            //PointEvent<TPayload> pointEvent=base.CreateInsertEvent();
            //pointEvent.Payload = (TPayload)Activator.CreateInstance(typeof(TPayload));
          
            //Not sure if this is for, some of the samples were doing this
            //need to research more

            //pointEvent.StartTime = DateTime.Now;

            //This is where the actual event is being queued in CEP
            //Right now the data is null so I get an error
            //need to set those values and I should be good to go

            //Enqueue(ref pointEvent);
           

            return retVal;
        }
    }

    [ServiceContract]
    public interface ISimplelWcfEventType
    {
        [OperationContract]
        string SubmitReading(string MeterId, double Value, DateTime Timestamp);
    }

}
